home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / system / altvw15.zip / ALTVIEW.PAS < prev    next >
Pascal/Delphi Source File  |  1995-02-01  |  28KB  |  818 lines

  1. {                 Alternative viewer for Norton Commander 4.0                 }
  2. {                                                                             }
  3. {       Copyright (C) 1994, 1995 Tomá¿ Hajnÿ, XHajT03@vse.cz on Internet      }
  4. {                                                                             }
  5. {  Unit Spawno (swapping itself from conventional memory when calling viewer; }
  6. {  only approximately 400 bytes remains !!!) Copyright (C) 1990-2 Ralf Brown, }
  7. {    ralf@cs.cmu.edu - many thanks for this. Source code (C and assembler)    }
  8. {              available on Simtel and its mirrors (directory C).             }
  9. {                                                                             }
  10. {      Original compilation with BP 7.0 and a fast replacement library,       }
  11. {      Copyright (C) 1988-1994 Norbert Juffa, norbert@iit.com - thanks.       }
  12. {         Available on Simtel and its mirrors (directory TurboPas).           }
  13. {                                                                             }
  14. {   You may freely use and distribute this program. If you wish to modify it, }
  15. { you must let the user know that the code has been changed and you must keep }
  16. { my name here. You can't sell neither the program nor anything based on my   }
  17. { code. (Do you like FSF's rules? Me too - they're great!)                    }
  18. {   Everybody distributing the program must be able to distribute this source }
  19. { file as well.                                                               }
  20. {   This program is a solution for users of NC 4.0, as well as for users of   }
  21. { some archive viewers those call one viewer for every file in the archive.   }
  22. {   Feel free to use e-mail adress above if you have any questions, problems  }
  23. { or suggestions.                                                             }
  24. {                                                                             }
  25. {      1) Installation                                                        }
  26. {                                                                             }
  27. {   The program breaks the limit of 10 viewers for NC 4.0. You simply remove  }
  28. { one of the viewers in your NC.CFG file (you don't lose this viewer, because }
  29. { you can write it later into the ALTVIEW.CFG), then write new section for    }
  30. { this 'viewer' (~ALTVIEW.EXE) AFTER (!) wpview.exe (i.e. it will be the last }
  31. { one except two graphic viewers) and move the $*.* specification from the    }
  32. { section of ~WPVIEW.EXE to this new section. The program (like other viewers }
  33. { in NC 4.0) must reside in the directory of NC, as well as the configuration }
  34. { file, i.e. file with the same name and the extension .CFG.                  }
  35. {                                                                             }
  36. {      2) Configuration file                                                  }
  37. {                                                                             }
  38. {   The structure of the configuration file is similar as in NC.CFG of NC 4.0 }
  39. { (i.e. it's a text file editable by any editor). Every line not beginning    }
  40. { with '~', '$', '%', '+' or '&' is ignored. Characters '~' and '%' must be   }
  41. { immediately followed with a name of the viewer (without spaces and path!).  }
  42. { The following line(s) starting with characters '$', '+' and '&' up to       }
  43. { another '~' or '%' characters are the patterns of files for this viewer     }
  44. { (e.g. $*.ext). If there is more than one pattern matching the viewed file,  }
  45. { the first one is used; the exception is the case of '&' at the begin of the }
  46. { line - then you can select one of all viewers having pattern matching the   }
  47. { viewed file. Use a '%' before a viewer name when you use it from NC 4.0 and }
  48. { the viewer doesn't have enough memory - normally viewers are called from    }
  49. { NCMAIN.EXE; in case of '%', a temporary batch file is created and then      }
  50. { called from command line - this causes NCMAIN.EXE to be terminated (not     }
  51. { NC.EXE) and then reloaded. If you use a '+' character before the pattern,   }
  52. { only a file name is given to the viewer, not full path (e.g. MODPLAY needs  }
  53. { this - don't ask me why). The last viewer should be WPVIEW.EXE with pattern }
  54. { $*.* for files not matching any other pattern.                              }
  55. {                                                                             }
  56. {      3) Limitations                                                         }
  57. {                                                                             }
  58. {   Yes, there are problems (known). If compiled with SPAWNO, it is no longer }
  59. { possible to use Quick view (in NC); it's a bug in SPAWNO and I can't do     }
  60. { anything against that. As well, NC doesn't know, it should load another     }
  61. { viewer when Quick view is open and you move the cursor from one to another  }
  62. { file and both are handled by ALTVIEW, i.e. it uses the same viewer for all  }
  63. { files as long as you don't move the cursor to the file handled by another   }
  64. { viewer (but I don't know viewers able to handle Quick view except the       }
  65. { original ones - if you do, let me know about them) or to the directory. It  }
  66. { is NC's behaving - not ALTVIEW's. Another not very pleasant thing is that   }
  67. { after viewing a file with a viewer called from temporary batch file         }
  68. { (viewers which need more memory) the cursor isn't more on its original      }
  69. { position but goes to the top of the directory. The only way how to change   }
  70. { this is creating the batch file in some directory on the path (e.g. in the  }
  71. { directory of NC as it was in previous release) - then there would be no     }
  72. { need to change the current directory and this wouldn't occur; but I feel it }
  73. { is not very 'clear' to write temporary files into directory of executables  }
  74. { and in many cases this directory may be read only (e.g. on LANs, or when    }
  75. { somebody has set Disk Manager partitions read only). That's why I think     }
  76. { it's better to do this this way - if you think something else about this    }
  77. { (or have other idea how to solve this), send me an e-mail message. And,     }
  78. { last, but not least, I know there is a 'limitation' in my English and there }
  79. { are many mistakes in this documentation - excuse me for that.               }
  80. {                                                                             }
  81. {      4) Changes in this version (from 1.40, first "official" release)       }
  82. {                                                                             }
  83. { - You can press ESC or F10 to end the selection of the viewer and exit      }
  84. {  immediately.                                                               }
  85. { - Fixed a (possible, but very unlikely) problem with temporary file set to  }
  86. {  Read only.                                                                 }
  87. { - Fixed a bug with naming of temporary batch file; '{' is used when viewed  }
  88. {  file has no extension.                                                     }
  89. { - The batch file is now created in temporary (or current if neither TEMP    }
  90. {  nor TMP system variables are set) directory, not in that of ALTVIEW. (Have }
  91. {  someone already told you, it is good to have at least one of these         }
  92. {  variables set to select a directory for all temporary files, and to delete }
  93. {  the contents of it - files possibly staying here - every time you start up }
  94. {  your computer - i.e. from AUTOEXEC? Useful not only for Altview, but       }
  95. {  generally - NC uses this variable as well, DOS too; ... well, YOU probably }
  96. {  knew it, but there could be somebody ...).                                 }
  97. { - It is checked if all writes to batch file were succesful - if not (e.g.   }
  98. {  due not enough space on the disk), the batch file is erased.               }
  99. { - Color and other settings from NC now used when selecting a viewer.        }
  100. { - Fixed a small bug in searching for configuration file.                    }
  101. { - Better checking if it is safe to use "raw" extended memory (without XMS)  }
  102. {  for swapping, i.e. if not under MS Windows.                                }
  103. { - It is now possible to specify a batch file as a viewer in ALTVIEW.CFG     }
  104. {  (but there is no way how to give all parameters including the color setup  }
  105. {  and Quick view status from NC to the viewer called from the batch file -   }
  106. {  well, of course there is a way, but it's very very dirty); if your viewer  }
  107. {  called from the batch files needs these parameters, it's better to write   }
  108. {  a small program, which does everything what should do the batch file, and  }
  109. {  then executes the viewer with all its parameters.                          }
  110. { - You doesn't have to specify the extension of the viewer any more - in     }
  111. {  this case the normal DOS order of searching for the executables is used    }
  112. {  (COM, EXE, BAT).                                                           }
  113. { - Made it possible to specify additional parameters for the viewer after    }
  114. {  its name.                                                                  }
  115. { - Added support for mouse (when selecting a viewer).                        }
  116. {                                                                             }
  117. {                                                     That's all.             }
  118. {                                                                             }
  119. { Of course, there is no warranty, either express or implied, about this      }
  120. { program and you use it at your own risk. (Stupid message, but who knows...) }
  121.  
  122. program AltView;
  123. { $DEFINE QUICKVIEW} (* if you delete the space before '$', the program will *)
  124.                      (* have less memory to execute viewers, but it will be  *)
  125.                      (* able to use Quick view in NC - see above             *)
  126. {$IFNDEF QUICKVIEW}
  127. {$M 4096,73000,73000}
  128. {$ELSE}
  129. {$M 4096,98000,98000}
  130. {$ENDIF}
  131. (* so much memory allocated to ensure, at least wpview can be started;       *)
  132. (* you can change this number if you use another text viewer - but be sure   *)
  133. (* to have enough memory for handling dynamically allocated variables, i.e.  *)
  134. (* the list of viewers possible for particular file extension                *)
  135.  
  136. {$G+,A+,R-,S-,B-,F-,L-,V-}
  137. {$D-}
  138.  
  139. uses
  140. {$IFNDEF QUICKVIEW}
  141.  Spawno,
  142. {$ENDIF}
  143.  Crt, Dos, Memory;
  144. (* procedure SetMemTop (allocates and deallocates heap memory) is in unit   *)
  145. (* Memory from Turbo Vision; if you replace this routine, you don't need    *)
  146. (* this unit and you can compile the program with TP prior to version 6.0   *)
  147. (* (but at least 5.0 - I think, TP 4.0 doesn't have environment handling)   *)
  148.  
  149. type
  150.  FileStr = string [12];
  151.  PVRec = ^VRec;
  152.  VRec = record
  153.   VName: FileStr;
  154.   Next: PVRec;
  155.   Pars: string [20];
  156.   Big: boolean;
  157.  end;
  158.  TPB = ^byte;
  159.  CRec = record
  160.   TF, TB, CF, CB, FF: byte;
  161.  end;
  162.  
  163. var
  164.  VideoMode: byte absolute 0:$0449;
  165.  R: Registers;
  166.  Cfg: text;
  167.  B: text;
  168.  T: file;
  169.  TPath, TName: PathStr;
  170.  Pars: string [20];
  171.  ODir: DirStr;
  172.  CfgName: PathStr;
  173.  Dir, OwnDir: DirStr;
  174.  Name: NameStr;
  175.  Ext, VExt: ExtStr;
  176.  Viewer: PathStr;
  177.  I, J, Y: byte;
  178.  SR: SearchRec;
  179.  EnvPath: string;
  180.  Pattern: string;
  181.  FName: PathStr;
  182.  VName: PathStr;
  183.  BV: PathStr;
  184.  VA: array [1..5] of FileStr;
  185.  OldX, OldY, OldC, OldB: byte;
  186.  XX: string;
  187.  Status: integer;
  188.  ParP: pointer;
  189.  PB: TPB absolute ParP;
  190.  ContStr2: string [2];
  191.  
  192. const
  193.  Found: boolean = false;
  194.  Sec: boolean = false;
  195.  Params: string = '';
  196.  Line: string = '';
  197.  ContStr1: string [3] = '$&+';
  198.  ViewStr: string [2] = '~%';
  199.  EditStr: string [1] = '@';
  200.  VNum: word = 0;
  201.  First: PVRec = nil;
  202.  Act: PVRec = nil;
  203.  Big: boolean = false;
  204.  Direct: boolean = false;
  205.  ExtKey: char = #0;
  206.  IsMouse: boolean = false;
  207.  Button: byte = 1;
  208.  CI: byte = 1;
  209.  CArray: array [0..3] of CRec = ((TF:  7; TB: 0; CF:  0; CB: 7; FF: 15),
  210.                                  (TF: 11; TB: 1; CF:  0; CB: 3; FF: 14),
  211.                                  (TF:  7; TB: 0; CF:  0; CB: 7; FF: 15),
  212.                                  (TF: 15; TB: 1; CF: 15; CB: 3; FF: 10));
  213.                               (* ^^^ four color combinations from NC 4.0 *)
  214.  
  215. function ExtKeyPressed: boolean;   (* 'key' is here as well e.g. a shift *)
  216. var
  217.  Is: boolean;
  218.  Shifts1: byte absolute $40:$17;   (* shift status as set by BIOS *)
  219.  Shifts2: byte absolute $40:$18;   (* (extended and normal)       *)
  220. begin
  221.  Is := false;
  222.  asm
  223.   mov ah, 11h
  224.   int 16h
  225.   jz @@1
  226.   mov [Is], true
  227.   mov ah, 10h
  228.   int 16h
  229. @@1:
  230.  end;
  231.  ExtKeyPressed := Is or (Shifts1 and $0F <> 0) or (Shifts2 <> 0);
  232. end;
  233.  
  234. procedure LookT;
  235. var
  236.  DW, HS: word;
  237.  DT: DateTime;
  238.  L, M: Longint;
  239. begin
  240.  if ((WhereX = (Lo (WindMax) div 2) + 2) or (WhereX = 1)) and
  241.             (WhereY = Hi (WindMax) - 1) or (Length (Params) >= 18) and
  242.                                          (Params [18] = '(') then Sec := true;
  243. {$I-}                           (* ^^^ started as Quick view ^^^ *)
  244.  Reset (T);
  245.  if IOResult = 0 then           (* there is already a temporary file *)
  246.  begin
  247.   GetFTime (T, L);
  248.   with DT do
  249.   begin
  250.    GetDate (Year, Month, Day, DW);
  251.    GetTime (Hour, Min, Sec, HS);
  252.   end;
  253.   PackTime (DT, M);
  254.   if M - L > 4096 then   (* temporary file older than 4 hours - it must have *)
  255.   begin                  (* remained after a system crash or a forced ending *)
  256.    TName [byte (TName [0]) + 1] := #0;           (* of some previous calling *)
  257.    Inc (TName [0]);                              (* - rewrite or reuse it    *)
  258.    asm
  259.     mov dx, OFFSET TName      (* setting attribute of the old temporary file *)
  260.     mov ah, 43h               (* to normal; for the case, somebody has set   *)
  261.     mov al, 1                 (* it read only - maybe a small joke or        *)
  262.     mov cx, 0                 (* an inadvertancy                             *)
  263.     int 21h
  264.    end;
  265.    Dec (TName [0]);
  266.    if Sec = true then
  267.    begin
  268.     Close (T);
  269.     Erase (T);
  270.    end else SetFTime (T, M);
  271.   end else Sec := true;
  272.   Close (T);
  273.  end else
  274.  begin
  275.   if Sec = false then
  276.   begin
  277.    Rewrite (T);
  278.    Close (T);
  279.   end;
  280.  end;
  281.  L := IOResult;
  282. {$I+}
  283. end;
  284.  
  285. procedure WriteStrDos (X: string);       (* enables redirection - WriteLn *)
  286. begin                                    (* handled by Crt unit           *)
  287.  XX := X + '$';
  288.  asm
  289.   mov ah, 9
  290.   mov dx, OFFSET XX
  291.   inc dx
  292.   int 21h
  293.  end;
  294. end;
  295.  
  296. procedure NoCfg;
  297. begin
  298.  WriteStrDos ('Cannot open ' + CfgName);
  299.  WriteLn;
  300.  repeat until (ExtKeyPressed);
  301.  Halt (3);
  302. end;
  303.  
  304. procedure DelT;
  305. begin
  306.  if not (Sec) then
  307.  {$I-}
  308.  Erase (T);
  309.  {$I+}
  310. end;
  311.  
  312. procedure Disp;                     (* disposing allocated memory - if any *)
  313. begin
  314.  while First <> nil do
  315.  begin
  316.   Act := First^.Next;
  317.   Dispose (First);
  318.   First := Act;
  319.  end;
  320. end;
  321.  
  322. {$IFNDEF QUICKVIEW}
  323. function SwapType: byte;
  324. begin
  325.  R.AX := $1600;
  326.  Intr ($2F, R);
  327.  if R.AL <> 0 then SwapType := Swap_All xor Swap_Ext else
  328.  begin
  329.   R.AX := $160A;                 (* cannot use swapping into "raw" extended *)
  330.   R.BX := 0;                     (* memory (without XMS) under MS Windows   *)
  331.   Intr ($2F, R);
  332.   if (R.AX = 0) and (R.BH <> 0) then SwapType := Swap_All xor Swap_Ext
  333.                                                     else SwapType := Swap_All;
  334.  end;
  335. end;
  336. {$ENDIF}
  337.  
  338. function Which: FileStr;           (* manual selection of the right viewer *)
  339. var
  340.  Y1: byte;
  341.  C: char;
  342.  
  343.  procedure ShowMouse; assembler;
  344.  asm
  345.   mov ax, 1
  346.   int 33h
  347.  end;
  348.  
  349.  procedure HideMouse; assembler;
  350.  asm
  351.   mov ax, 2
  352.   int 33h
  353.  end;
  354.  
  355.  function ExtReadKey: char;
  356.  var
  357.   Pressed: boolean;
  358.   MX, MY: byte;
  359.  begin
  360.   if not (IsMouse) then ExtReadKey := ReadKey else
  361.   begin
  362.    if ExtKey <> #0 then
  363.    begin
  364.     ExtReadKey := ExtKey;
  365.     ExtKey := #0;
  366.    end else
  367.    begin
  368.     Pressed := false;
  369.     while not (Pressed) do
  370.     begin
  371.      if KeyPressed then
  372.      begin
  373.       ExtReadKey := ReadKey;
  374.       Pressed := true;
  375.      end else
  376.      begin
  377.       R.AX := 3;
  378.       Intr ($33, R);
  379.       if R.BX and Button <> 0 then
  380.       begin
  381.        Pressed := true;
  382.        MX := R.CX div 8 + 1;
  383.        MY := R.DX div 8 + 1;
  384.        if (MX < 35) or (MX > 46) or (MY < 7 - J) or (MY > 8) then
  385.                                                          ExtReadKey := #27 else
  386.        if (MY > 7 - J) and (MY < 8) then
  387.        begin
  388.         ExtReadKey := #13;
  389.         Y := MY + J - 7;
  390.        end else
  391.        begin
  392.         ExtReadKey := #0;
  393.         if MY = 8 then ExtKey := #81 else ExtKey := #73;
  394.        end
  395.       end;
  396.      end;
  397.     end;
  398.    end;
  399.   end;
  400.  end;
  401.  
  402. begin
  403.  if VNum > 5 then J := 5 else J := VNum;
  404.  Act := First;
  405.  TextBackground (CArray [CI].TB);
  406.  TextColor (CArray [CI].FF);
  407.  if IsMouse then HideMouse;
  408.  GotoXY (34, 7 - J);
  409.  Write ('╔════════════╗');
  410.  for I := 1 to J do
  411.  begin
  412.   VA [I] := Copy (Act^.VName + '            ', 1 , 12);
  413.   Act := Act^.Next;
  414.   GotoXY (34, 7 - J + I);
  415.   Write ('║            ║');
  416.  end;
  417.  GotoXY (34, 8);
  418.  Write ('╚════════════╝');
  419.  if IsMouse then ShowMouse;
  420.  Y := 1;
  421.  Y1 := 0;
  422.  TextColor (CArray [CI].TF);
  423.  repeat
  424.   if IsMouse then HideMouse;
  425.   for I := 1 to J do
  426.   begin
  427.    GotoXY (35, 7 - J + I);
  428.    Write (VA [I]);
  429.   end;
  430.   TextColor (CArray [CI].CF);
  431.   TextBackground (CArray [CI].CB);
  432.   GotoXY (35, 7 - J + Y);
  433.   Write (VA [Y]);
  434.   TextColor (CArray [CI].FF);
  435.   TextBackground (CArray [CI].TB);
  436.   GotoXY (45, 7 - J);
  437.   if Y1 > 0 then Write (#24) else Write (#205);       (* some viewers above? *)
  438.   GotoXY (45, 8);
  439.   if Y1 + J < VNum then Write (#25) else Write (#205); (* even more viewers? *)
  440.   TextColor (CArray [CI].TF);
  441.   if IsMouse then ShowMouse;
  442.   C := ExtReadKey;
  443.   if C = #0 then
  444.   begin
  445.    C := ExtReadKey;
  446.    case C of         
  447.     #68: C := #27;  (* F10 acts the same way as Escape - quit the selection  *)
  448.     #61: C := #13;  (* F3 acts the same way as Enter; this makes it possible *)
  449.                     (* to select the first viewer when this key is held down *)
  450.     #72: if Y > 1 then Dec (Y) else if Y1 > 0 then Dec (Y1) else     (* Up   *)
  451.          begin
  452.           Y := J;
  453.           Y1 := VNum - J;
  454.          end;
  455.     #80: if Y < J then Inc (Y) else if Y + Y1 < VNum then            (* Down *)
  456.                                                       Inc (Y1) else
  457.          begin
  458.           Y1 := 0;
  459.           Y := 1;
  460.          end;
  461.     #71: begin                                                       (* Home *)
  462.           Y1 := 0;
  463.           Y := 1;
  464.          end;
  465.     #79: begin                                                       (* End  *)
  466.           Y := J;
  467.           Y1 := VNum - J;
  468.          end;
  469.     #73: if Y + Y1 <= J then                                         (* PgUp *)
  470.          begin
  471.           Y1 := 0;
  472.           Y := 1;
  473.          end else if Y1 >= J then Dec (Y1, J) else
  474.          begin
  475.           Dec (Y, J - Y1);
  476.           Y1 := 0;
  477.          end;
  478.     #81: if VNum - Y - Y1 < J then                                   (* PgDn *)
  479.          begin
  480.           Y := J;
  481.           Y1 := VNum - J;
  482.          end else if VNum - Y1 >= 2 * J then Inc (Y1, J) else
  483.          begin
  484.           Inc (Y, 2 * J - VNum + Y1);
  485.           Y1 := VNum - J;
  486.          end else C := #0;
  487.    end;
  488.    if C > #0 then              (* redraw *)
  489.    begin
  490.     I := 0;
  491.     Act := First;
  492.     while I < Y1 do
  493.     begin
  494.      Act := Act^.Next;
  495.      Inc (I);
  496.     end;
  497.     for I := 1 to J do
  498.     begin
  499.      VA [I] := Copy (Act^.VName + '            ', 1 , 12);
  500.      Act := Act^.Next;
  501.     end;
  502.    end;
  503.   end;
  504.  until (C = #13) or (C = #27);
  505.  if C = #27 then
  506.  begin
  507.   Disp;
  508.   DelT;
  509.   Halt (0);
  510.  end;
  511.  I := 1;
  512.  Act := First;
  513.  while I < Y + Y1 do
  514.  begin
  515.   Act := Act^.Next;
  516.   Inc (I);
  517.  end;
  518.  VName := Act^.VName;
  519.  Which := VName;
  520.  Big := Act^.Big;
  521.  Pars := Act^.Pars;
  522.  TextColor (OldC);
  523.  TextBackground (OldB);
  524. end;
  525.  
  526. begin
  527.  if Lo (DosVersion) < 3 then Viewer := 'ALTVIEW.EXE' else
  528.  begin
  529.   Viewer := FExpand (ParamStr (0));
  530.   ParP := Ptr (PrefixSeg, $80);         (* get the string of parameters      *)
  531.   Move (ParP^, Params, PB^ + 1);        (* from PSP (Program Segment Prefix) *)
  532.   I := Pos (#0, Params);
  533.   if I = 0 then Params := '' else
  534.                           Params := Copy (Params, I, Length (Params) - I + 1);
  535.  end;
  536.  if Length (Params) >= 10 then
  537.  begin
  538.   CI := byte (Params [10]);
  539. {$IFNDEF QUICKVIEW}
  540.   if ((CI = 1) or (CI = 3)) and (VideoMode = 2) then VideoMode := 3;
  541. {$ENDIF}
  542.  end else if (VideoMode = 0) or (VideoMode = 2) or (VideoMode = 7) then
  543.                                                                        CI := 0;
  544.  if Length (Params) >= 14 then
  545.  begin
  546.   IsMouse := boolean (Params [14]);
  547.   Button := byte (Params [13]) + 1;
  548.  end else
  549.  begin
  550.   R.AX := 0;
  551.   Intr ($33, R);
  552.   if R.AX = $FFFF then IsMouse := true;
  553.  end;
  554.  GetDir (0, ODir);
  555.  FSplit (Viewer, OwnDir, Name, Ext);
  556.  CfgName := Dir + Name + '.CFG';
  557.  FindFirst (CfgName, $27, SR);
  558.  if DosError <> 0 then
  559.  begin
  560.   EnvPath := GetEnv ('PATH');
  561.   if EnvPath = '' then NoCfg;
  562.   Dir := '';
  563.   I := 1;
  564.   J := 0;
  565.   while (Dir = '') and (I > 0) do
  566.   begin
  567.    I := Pos (';', Copy (EnvPath, J + 1, Length (EnvPath) - J));
  568.    if I > 0 then
  569.    begin
  570.     Dir := Copy (EnvPath, J + 1, I - 1) + '\';
  571.     FindFirst (Dir + Name + '.CFG', $27, SR);
  572.     if DosError <> 0 then Dir := '';
  573.    end;
  574.    J := J + I;
  575.   end;
  576.   if Dir = '' then NoCfg;
  577.  end;
  578.  CfgName := Dir + Name + '.CFG';
  579.  Assign (Cfg, CfgName);
  580.  TPath := GetEnv ('TEMP');
  581.  if TPath = '' then
  582.  begin
  583.   TPath := GetEnv ('TMP');
  584.   if TPath = '' then TPath := '.';
  585.  end;
  586. {$IFNDEF QUICKVIEW}
  587.  Init_SpawnO (TPath, SwapType, 20, 0);
  588. {$ENDIF}
  589.  TPath := FExpand (TPath);
  590.  TName := TPath + '\' + Name + '.TMP';
  591.  Assign (T, TName);
  592.  {$I-}
  593.  Reset (Cfg);
  594.  if IOResult <> 0 then NoCfg;
  595.  LookT;
  596.  {$I+}
  597.  FName := ParamStr (1);
  598.  FName [2] := UpCase (FName [2]);          (* well - 'undocumented' option;  *)
  599.  if (FName = '/E') or (FName = '-E') then  (* this makes it possible to use  *)
  600.  begin                                     (* ALTVIEW to start an editor for *)
  601.   FName := ParamStr (2);                   (* specific file pattern or to    *)
  602.   ContStr2 := EditStr;                     (* have another set of vievers;   *)
  603.  end else ContStr2 := ViewStr;             (* this needs special ALTVIEW.CFG *)
  604.  FName := FExpand (FName);
  605.  FSplit (FName, Dir, Name, Ext);
  606.  while not (Found) and not (Eof (Cfg)) do
  607.  begin
  608.   while not (Eof (Cfg)) and (Pos (Copy (Line, 1, 1), ContStr2) = 0) do
  609.                                                          ReadLn (Cfg, Line);
  610.   if Eof (Cfg) then Viewer := '' else
  611.   begin
  612.    Big := false;
  613.    Pars := '';
  614.    J := Pos (' ', Line);
  615.    if J = 0 then J := Length (Line) + 1 else
  616.    begin
  617.     while Line [Length (Line)] = ' ' do Dec (Line [0]);
  618.     if Length (Line) - J > 20 then Line [0] := char (J + 20);
  619.     Pars := Copy (Line, J + 1, Length (Line) - J) + ' ';
  620.    end;
  621.    VName := Copy (Line, 2, J - 2);
  622.    Viewer := OwnDir + VName;
  623.    if (Line [1] = '%') and not (Sec) then Big := true;
  624.   end;
  625.   if Viewer <> '' then
  626.   begin
  627.    repeat
  628.     repeat ReadLn (Cfg, Line) until Eof (Cfg)
  629.                         or (Pos (Line [1], ContStr1 + ViewStr + EditStr) > 0);
  630.     if (Pos (Line [1], ContStr1) > 0) then
  631.     begin
  632.      Pattern := Copy (Line, 2, Length (Line) - 1);
  633.      FindFirst (Dir + Pattern, $27, SR);
  634.      I := VNum;
  635.      while (DosError = 0) and (VNum = I) and not (Found) do
  636.      begin
  637.       if SR.Name = Name + Ext then
  638.       begin
  639.        if Line [1] = '&' then
  640.        begin
  641.         if VNum = 0 then
  642.         begin
  643.          Inc (VNum);
  644.          New (First);
  645.          First^.VName := VName;
  646.          First^.Big := Big;
  647.          First^.Pars := Pars;
  648.          First^.Next := nil;
  649.         end else
  650.         begin
  651.          Act := First;
  652.          I := 0;
  653.          while (I < VNum) do
  654.          begin
  655.           if Act^.VName = VName then I := VNum + 1 else
  656.           begin
  657.            Inc (I);
  658.            if Act^.Next <> nil then Act := Act^.Next;
  659.           end;
  660.          end;
  661.          if I = VNum then
  662.          begin
  663.           New (Act^.Next);
  664.           Act := Act^.Next;
  665.           Act^.VName := VName;
  666.           Act^.Big := Big;
  667.           Act^.Pars := Pars;
  668.           Act^.Next := nil;
  669.           Inc (VNum);
  670.          end;
  671.         end;
  672.        end else
  673.        if VNum = 0 then
  674.        begin
  675.         if Line [1] = '+' then Direct := true;
  676.         Found := true;
  677.         Disp;
  678.        end;
  679.       end;
  680.       FindNext (SR);
  681.      end;
  682.     end;
  683.    until Eof (Cfg) or (Pos (Line [1], ViewStr) > 0) or Found;
  684.   end;
  685.  end;
  686.  Close (Cfg);
  687.  OldX := WhereX;
  688.  OldY := WhereY;
  689.  OldC := TextAttr and $8f;
  690.  OldB := (TextAttr and $70) div 16;
  691.  if Direct then
  692.  begin
  693.   FName := Name + Ext;
  694.   ChDir (Copy (Dir, 1, Length (Dir) - 1));
  695.  end;
  696.  FName := Pars + FName;
  697.  if (VNum > 0) and not (Found) then
  698.  begin
  699.   if VNum > 1 then Viewer := OwnDir + Which else
  700.   begin
  701.    VName := First^.VName;
  702.    Big := First^.Big;
  703.    Pars := First^.Pars;
  704.    Viewer := OwnDir + VName;
  705.   end;
  706.   Disp;
  707.   Found := true;
  708.  end;
  709.  if Found then
  710.  begin
  711.   GotoXY (OldX, OldY);
  712.   if not (Sec) and (ContStr2 = ViewStr) then
  713.   begin
  714.    WriteStrDos (Copy (VName + '           ', 1, 12));
  715.    GotoXY (OldX, OldY);
  716.   end;
  717.   SetMemTop (HeapPtr);
  718.   VExt := Copy (Viewer, Length (Viewer) - 3, 4);
  719.   for I := 2 to 4 do VExt [I] := UpCase (VExt [I]);
  720.   if not (Big) then
  721.   begin
  722.    SwapVectors;
  723. {$IFNDEF QUICKVIEW}
  724.    if VExt = '.BAT' then Status := Spawn (GetEnv ('COMSPEC'), '/C ' + Viewer +
  725.      ' ' + FName + Params, 0) else Status := Spawn (Viewer, FName + Params, 0);
  726.    if (Status = -1) and (Spawno_error = -2) and (Pos ('.', VExt) = 0) then
  727.       Status := Spawn (GetEnv ('COMSPEC'), '/C ' + Viewer + '.BAT ' + FName +
  728.                                                                     Params, 0);
  729.    if Status = -1 then
  730. {$ELSE}
  731.    if Pos ('.', VExt) = 0 then
  732.    begin
  733.     Exec (Viewer + '.COM', FName + Params);
  734.     if DosError <> 0 then
  735.     begin
  736.      Exec (Viewer + '.EXE', FName + Params);
  737.      if DosError <> 0 then Exec (GetEnv ('COMSPEC'), '/C' + Viewer + '.BAT ' +
  738.                                                                FName + Params);
  739.     end;
  740.    end else
  741.    if VExt = '.BAT' then Exec (GetEnv ('COMSPEC'), '/C ' + Viewer + ' ' +
  742.                             FName + Params) else Exec (Viewer, FName + Params);
  743.    if DosError <> 0 then
  744. {$ENDIF}
  745.    begin
  746.     WriteStrDos ('Cannot execute ' + Viewer + '!!');
  747.     WriteLn;
  748.     repeat until (ExtKeyPressed);
  749. {$IFNDEF QUICKVIEW}
  750.     Status := Spawn (OwnDir + 'WPVIEW.EXE', Dir + Name + Ext + Params, 0);
  751.     if Status = -1 then
  752. {$ELSE}
  753.     Exec (OwnDir + 'WPVIEW.EXE', Dir + Name + Ext + Params);
  754.     if DosError <> 0 then
  755. {$ENDIF}
  756.     begin
  757.      SwapVectors;
  758.      DelT;
  759.      Halt (8);
  760.     end;
  761.    end else ChDir (ODir);
  762.    SwapVectors;
  763.    DelT;
  764.   end else
  765.   begin
  766.    BV := Copy (Ext, 2, 3);
  767.    if BV = '' then BV := '{';
  768.    BV := BV + '.BAT';
  769.    GetDir (byte (TPath [1]) - 64, XX);
  770.    Assign (B, TPath + '\' + BV);
  771. {$I-}
  772.    Rewrite (B);
  773.    WriteLn (B, '@ECHO OFF');
  774.    WriteLn (B, 'CD ' + XX);
  775.    WriteLn (B, Copy (ODir, 1, 2));
  776.    if VExt = '.BAT' then WriteLn (B, 'CALL ' + Viewer + ' ' + FName) else
  777.                                              WriteLn (B, Viewer + ' ' + FName);
  778.    WriteLn (B, 'DEL ' + TName);
  779.    Write (B, 'DEL ' + TPath + '\' + BV);
  780.    if IOResult <> 0 then
  781.    begin
  782.     Close (B);
  783.     Erase (B);
  784.    end else Close (B);
  785. {$I+}
  786.    asm
  787. @1:
  788.     mov ah, 11h
  789.     int 16h
  790.     jz @2
  791.     mov ah, 10h
  792.     int 16h
  793.     jmp @1
  794. @2:
  795.    end;
  796.    Dec (BV [0], 4);
  797.    BV := BV + ' ' + Name;
  798.    for I := 1 to Length (BV) do
  799.    begin
  800.     R.AH := 5;
  801.     R.CL := Ord (BV [I]);
  802.     Intr ($16, R);
  803.    end;
  804.    R.AH := 5;
  805.    R.CL := 13;
  806.    R.CH := $1C;
  807.    Intr ($16, R);
  808.    ChDir (TPath);
  809.   end;
  810.  end else
  811.  begin
  812.   WriteStrDos ('No matching pattern found!!');
  813.   WriteLn;
  814.   repeat until (ExtKeyPressed);
  815.   DelT;
  816.   Halt (2);
  817.  end;
  818. end.